package utils;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.Map.Entry;
import config.ConfigManager;
import exception.InvalidConfigException;

public abstract class ObjectCache<K, V> {
	private HashMap<K, V> cache;
	private HashMap<K, Long> time;
	private long ttl;
	private String cacheName;

	protected void initObjectCache() {
		cache = new HashMap<K, V>();
		time = new HashMap<K, Long>();
		String name = cacheName != null ? cacheName : "cache_time";
		try {
			ttl = (1000 * 60 * ConfigManager.getIntConfig(name));
		} catch (InvalidConfigException e) {
			e.printStackTrace();
			ttl = (1000 * 60 * 60); // la cache dura una hora
		}
	}
	
	public V find(K key) {
		ensureValidity();
		V ret = null;
		synchronized (cache) {
			ret = cache.get(key);
		}
		return ret;
	}

	public void putIn(K key, V value) {
		synchronized (cache) {
			cache.put(key, value);
		}
		synchronized (time) {
			time.put(key, Calendar.getInstance().getTimeInMillis());
		}
	}

	public V remove(K key) {
		synchronized (time) {
			time.remove(key);
		}
		synchronized (cache) {
			return cache.remove(key);
		}
	}

	public void clear() {
		synchronized (time) {
			time.clear();
		}
		synchronized (cache) {
			cache.clear();
		}
	}

	private void ensureValidity() {
		long now = Calendar.getInstance().getTimeInMillis();
		Set<Entry<K, Long>> entrySet = null;
		synchronized (time) {
			entrySet = time.entrySet();
		}
		List<K> toRemove = new ArrayList<K>();
		for (Entry<K, Long> entry : entrySet) {
			if (now - entry.getValue() >= ttl) {
				toRemove.add(entry.getKey());
			}
		}
		for (K key : toRemove) {
			remove(key);
		}
	}

	/**
	 * Acceso a cacheName
	 * @return valor del atributo cacheName
	 */
	public String getCacheName() {
		return cacheName;
	}

	/**
	 * Modificador de cacheName
	 * @param cacheName nuevo valor del atributo cacheName
	 */
	public void setCacheName(String cacheName) {
		this.cacheName = cacheName;
	}
}
